一道水题 下载源文件后点开是一个刮刮乐的图片,没有任何操作空间,查壳后扔进IDApro得到源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 INT_PTR __stdcall DialogFunc (HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; const char *v5; int v7[2 ]; int v8; int v9; int v10; int v11; int v12; int v13; int v14; int v15; int v16; CHAR String[65536 ]; char v18[65536 ]; if ( a2 == 272 ) return 1 ; if ( a2 != 273 ) return 0 ; if ( (_WORD)a3 == 1001 ) { memset (String, 0 , 0xFFFF u); GetDlgItemTextA(hDlg, 1000 , String, 0xFFFF ); if ( strlen (String) == 8 ) { v7[0 ] = 90 ; v7[1 ] = 74 ; v8 = 83 ; v9 = 69 ; v10 = 67 ; v11 = 97 ; v12 = 78 ; v13 = 72 ; v14 = 51 ; v15 = 110 ; v16 = 103 ; sub_4010F0(v7, 0 , 10 ); memset (v18, 0 , 0xFFFF u); v18[0 ] = String[5 ]; v18[2 ] = String[7 ]; v18[1 ] = String[6 ]; v4 = (const char *)sub_401000(v18, strlen (v18)); memset (v18, 0 , 0xFFFF u); v18[1 ] = String[3 ]; v18[0 ] = String[2 ]; v18[2 ] = String[4 ]; v5 = (const char *)sub_401000(v18, strlen (v18)); if ( String[0 ] == v7[0 ] + 34 && String[1 ] == v10 && 4 * String[2 ] - 141 == 3 * v8 && String[3 ] / 4 == 2 * (v13 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); } } return 0 ; } if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 ) return 0 ; EndDialog(hDlg, (unsigned __int16)a3); return 1 ; }
注意到sub_4010F0(v7, 0, 10);
应该是加密函数,点进去查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 int __cdecl sub_4010F0 (int a1, int a2, int a3) { int result; int i; int v5; int v6; result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = 4 * i; v6 = *(_DWORD *)(4 * i + a1); if ( a2 < result && i < result ) { do { if ( v6 > *(_DWORD *)(a1 + 4 * result) ) { if ( i >= result ) break ; ++i; *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result); if ( i >= result ) break ; while ( *(_DWORD *)(a1 + 4 * i) <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break ; v5 = 4 * i; *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1); } --result; } while ( i < result ); } LABEL_13: *(_DWORD *)(a1 + 4 * result) = v6; sub_4010F0(a1, a2, i - 1 ); result = a3; ++i; } return result; }
发现a2
和a3
是一段[0,11]区间,可是main函数里v7只有两个下标,于是盲猜v7-v16
地址是连在一起的,相当于一个数组。于是main函数的代码逻辑应该是:flag是string,通过
1 2 3 4 5 6 7 8 9 if ( String[0 ] == v7[0 ] + 34 && String[1 ] == v10 && 4 * String[2 ] - 141 == 3 * v8 && String[3 ] / 4 == 2 * (v13 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); }
判断是否正确,于是可以推出
1 2 3 4 5 string [0 ]=v7[0 ]+34 string [1 ]=v10string [2 ]=(3 *v8+141 )/4 string [3 ]=8 *(v13/9 )string [2 ,3 ,4 ],string [5 ,6 ,7 ]经过sub_401000加密后应该是"ak1w" ,"V1Ax"
sub_401000
明显是个base64
加密,那么只要知道sub_4010F0
即可得到flag。
v6 = *(_DWORD *)(4 * i + a1);
语句的意思是吧
于是直接开始写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <bits/stdc++.h> #define _DWORD unsigned char using namespace std;char v7[15 ]={90 ,74 ,83 ,69 ,67 ,97 ,78 ,72 ,51 ,110 ,103 };char flag[20 ];int sub (char *a1, int a2, int a3) { int result; int i; int v5; int v6; result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = i; v6 = *(_DWORD *)(i + a1); if ( a2 < result && i < result ) { do { if ( v6 > *(_DWORD *)(a1 + result) ) { if ( i >= result ) break ; ++i; *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + result); if ( i >= result ) break ; while ( *(_DWORD *)(a1 + i) <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break ; v5 = i; *(_DWORD *)(a1 + result) = *(_DWORD *)( i + a1); } --result; } while ( i < result ); } LABEL_13: *(_DWORD *)(a1 + result) = v6; sub (a1, a2, i - 1 ); result = a3; ++i; } return result; } int main () { sub (v7,0 ,10 ); cout<<v7<<endl; flag[0 ]=v7[0 ]+34 ; flag[1 ]=v7[4 ]; flag[2 ]=(3 *v7[2 ]+141 )/4 ; flag[3 ]=8 *(v7[7 ]/9 ); cout<<flag<<endl; }
得到v7字符串:3CEHJNSZagn
得到flag前四位:UJWP
接着对之前的两串字符进行base64转码后分别为jMp
和WP1
前后拼接上即可获得flag:UJMP1jMP